/**
 * Copyright (c) suzuki ryoutoku
 * See this code regarding the Apache License Version 2.0
 * @file StripCreator.cpp
 * @author suzuki ryoutoku
 */

//=============================================================================
//	pre processor
//=============================================================================
#include "StripCreator.h"
#include "Graphics.h"
#include <algorithm>

using namespace library::graphics;
using namespace strip;
using namespace library::log;

//=============================================================================
//	strip::Edge's method
//=============================================================================
/**
 * @author suzuki ryoutoku
 * @date 2007-11-2
 * @version 1.0
 */
Edge::Edge()
{
  this->_ascending = NULL;
  this->_descending = NULL;
}

/**
 * @author suzuki ryoutoku
 * @date 2007-11-2
 * @version 1.0
 */
Edge::~Edge()
{
}

/**
 * To search neighbour triabgle via edge
 * \note
 *
 *
 * @author suzuki ryoutoku
 * @date 2007-11-5
 * @version 1.0
 */
strip::Triangle* Edge::getNeighbourTriangle(strip::Triangle* face)
{
  if( face == this->_ascending ){
	return this->_descending;
  }else if( face == _descending ){
	return this->_ascending;
  }
  return NULL;
}

//=============================================================================
//	Triangle's method
//=============================================================================
/**
 * @author suzuki ryoutoku
 * @date 2007-11-2
 * @version 1.0
 */
Triangle::Triangle(int arg1, int arg2, int arg3)
{
  memset(this, 0, sizeof(strip::Triangle));
  this->_index[0] = arg1;
  this->_index[1] = arg2;
  this->_index[2] = arg3;
  this->_edges[0] = NULL;
  this->_edges[1] = NULL;
  this->_edges[2] = NULL;
}

/**
 * @author suzuki ryoutoku
 * @date 2007-11-2
 * @version 1.0
 */
Triangle::~Triangle()
{
}

/**
 * When second vertex is stored in virtual current buffer, 
 * this method search edge via which strip pass
 * \note
 * Presupposing connectivity order is clockwise.
 *
 * @param iedge previously via edge
 *
 * @return next edge via which strip pass.

 *
 * @author suzuki ryoutoku 
 * @date 2007-11-3
 * @version 1.0
 */
strip::Edge* Triangle::findViaEdgeWithCurrentBufferB(strip::Edge* iedge)
{

  int current_point = iedge->_second;
  if( this->_edges[0] == iedge ){
	// When strip previously passed from 0 to 1,
	// next, strip pass from 0 to 2.
	if( this->_edge_path[0] == false ){
	  current_point = iedge->_first;
	}
	if( this->_edges[2]->_first == current_point ||
		this->_edges[2]->_second == current_point ){
	  return this->_edges[2];

	}else if( this->_edges[1]->_first == current_point ||
			  this->_edges[1]->_second == current_point ){
	  return this->_edges[1];
	}
  }else if( this->_edges[1] == iedge ){
	// When strip previously passed from 1th edge to 2th edge,
	// next, strip pass from 0th edge to 1th edge.
	if( this->_edge_path[1] == false ){
	  current_point = iedge->_first;
	}
	if( this->_edges[2]->_first == current_point ||
		this->_edges[2]->_second == current_point ){
	  return this->_edges[2];

	}else if( this->_edges[0]->_first == current_point ||
			  this->_edges[0]->_second == current_point ){
	  return this->_edges[0];
	}
  }else{
	// When strip previously passed from 2th edge to 0th edge,
	// next, strip pass from 1th edge to 2th edge.
	if( this->_edge_path[2] == false ){
	  current_point = iedge->_first;
	}
	if( this->_edges[1]->_first == current_point ||
		this->_edges[1]->_second == current_point ){
	  return this->_edges[1];

	}else if( this->_edges[0]->_first == current_point ||
			  this->_edges[0]->_second == current_point ){
	  return this->_edges[0];
	}
	
  }

}

/**
 * When first vertex is stored in virtual current buffer, 
 * this method search edge via which strip pass.
 * \note
 * Presupposing connectivity order is clockwise.
 *
 * @param iedge previously via edge
 *
 * @return next edge via which strip pass.
 *
 * @author suzuki ryoutoku 
 * @date 2007-11-3
 * @version 1.0
 */
strip::Edge* Triangle::findViaEdgeWithCurrentBufferA(strip::Edge* iedge)
{
  int current_point = iedge->_first;
  if( this->_edges[0] == iedge ){
	// When strip previously passed from 0th edge to 1th edge,
	// next, strip pass from 0th edge to 2th edge.
	if( this->_edge_path[0] == false ){
	  current_point = iedge->_second;
	}
	if( this->_edges[2]->_first == current_point ||
		this->_edges[2]->_second == current_point ){
	  return this->_edges[2];

	}else if( this->_edges[1]->_first == current_point ||
			  this->_edges[1]->_second == current_point ){
	  return this->_edges[1];

	}
  }else if( this->_edges[1] == iedge ){
	// When strip previously passed from 1th edge to 2th edge,
	// next, strip pass from 0th edge to 1th edge.
	if( this->_edge_path[1] == false ){
	  current_point = iedge->_second;
	}
	if( this->_edges[2]->_first == current_point ||
		this->_edges[2]->_second == current_point ){
	  return this->_edges[2];

	}else if( this->_edges[0]->_first == current_point ||
			  this->_edges[0]->_second == current_point ){
	  return this->_edges[0];
	}
  }else{
	// When strip previously passed from 2th edge to 0th edge,
	// next, strip pass from 1th edge to 2th edge.
	if( this->_edge_path[2] == false ){
	  current_point = iedge->_second;
	}
	if( this->_edges[1]->_first == current_point ||
		this->_edges[1]->_second == current_point ){
	  return this->_edges[1];

	}else if( this->_edges[0]->_first == current_point ||
			  this->_edges[0]->_second == current_point ){
	  return this->_edges[0];
	}
	
  }
}

/**
 * To give vertex corresponding to edge.
 * \note
 *
 *
 * @author suzuki ryoutoku
 * @date 2007-11-7
 * @version 1.0
 */
int Triangle::getThitherVertex(strip::Edge* arg)
{
  if( this->_edges[0] == arg ){
	return this->_index[2];
  }else if( this->_edges[1] == arg ){
	return this->_index[0];
  }else if( this->_edges[2] == arg ){
	return this->_index[1];
  }
  return 0;
}

/**
 * To give vertex corresponding to triangle.
 * @author suzuki ryoutoku
 * @date 2007-11-7
 * @version 1.0
 */
int Triangle::getAcrossVertex(strip::Triangle* tri)
{
  if( tri->_edges[0] == this->_edges[0] ||
	  tri->_edges[1] == this->_edges[0] ||
	  tri->_edges[2] == this->_edges[0] ){
	return this->getThitherVertex(this->_edges[0]);

  }else if( tri->_edges[0] == this->_edges[1] ||
			tri->_edges[1] == this->_edges[1] || 
			tri->_edges[2] == this->_edges[1] ){
	return this->getThitherVertex(this->_edges[1]);

  }else if( tri->_edges[0] == this->_edges[2] || 
			tri->_edges[1] == this->_edges[2] || 
			tri->_edges[2] == this->_edges[2] ){
	return this->getThitherVertex(this->_edges[2]);

  }
  return 0;
}

/**
 * For debug.
 * @author r-suzuki
 * @date 2008-12-24
 * @version 1.0
 */
void Triangle::printAttrubite(void)
{
  cout << _face_index << ":" 
	   << _index[0] << "-" << _index[1] << "-" << _index[2] << " ";
  cout << _edges[0]->_first << "=>" << _edges[0]->_second << "(";
  if( _face_index != _edges[0]->_ascending->_face_index ) {
	cout << _edges[0]->_ascending->_face_index;
  }
  if( _face_index != _edges[0]->_descending->_face_index ){
	cout << _edges[0]->_descending->_face_index;
  }
  cout << ")";
  cout << _edges[1]->_first << "=>" << _edges[1]->_second << "(";
  if( _face_index != _edges[1]->_ascending->_face_index ){
	cout << _edges[1]->_ascending->_face_index;
  }
  if( _face_index != _edges[1]->_descending->_face_index ){
	cout << _edges[1]->_descending->_face_index;
  }
  cout << ")";
  cout << _edges[2]->_first << "=>" << _edges[2]->_second << "(";
  if( _face_index != _edges[2]->_ascending->_face_index){
	cout << _edges[2]->_ascending->_face_index;
  }
  if( _face_index != _edges[2]->_descending->_face_index ){
	cout << _edges[2]->_descending->_face_index;
  }
  cout << ")";
  cout << endl;

}

/**
 * This method notify adjustment triangle of leaving.
 * \note
 * This method's doing is to reduce Degree of adjustment triangle.
 * @author r-suzuki
 * @date 2009-1-5
 * @version 1.0
 */
void Triangle::notifyLeaving(void)
{
  for( int i = 0; i < 3; i ++ ){
	strip::Edge* edge = (this->_edges[i]);
	strip::Triangle* adjustment= edge->getNeighbourTriangle(this);
	if( adjustment == NULL ) continue;
	adjustment->_degree--;
  }
}

//=============================================================================
//	strip::Vertex's method
//=============================================================================
strip::Vertex::~Vertex()
{
  _tri_index.clear();
}

int strip::Vertex::getStartTriangle(vector<strip::Triangle>* _triangles)
{
  for( size_t i = 0; i < _tri_index.size(); i++ ){
	if( _triangles->at(_tri_index[i])._state != strip::Triangle::USED ){
	  return _tri_index[i];
	}
  }
  return -1;
}

//=============================================================================
//	StripCreatingOption's method
//=============================================================================
/**
 * 
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-7-3
 */
StripCreatingOption::StripCreatingOption(PolygonBody* body,
										 SelectStarting start_option) :
  _body(body),
  _start_option(start_option)
{
}

//=============================================================================
//	StripCrator's method
//=============================================================================
/**
 *
 * @author suzuki ryoutoku
 * @date 2007-10-30
 * @version 1.0
 */
StripCreator::StripCreator(library::log::LogManager* arg) :
	_logger(arg)
{
  char tmp[256];
  this->_logger->print("Creating Triangle strip\n Start time of creating strip =%s\n",
						this->_logger->storeTime(tmp));
}

/**
 * @author suzuki ryoutoku
 * @date 2007-10-30
 * @version 1.0
 */
StripCreator::~StripCreator()
{
  _edges.clear();
  _triangles.clear();
  _vertcies.clear();
  char tmp[256];
  this->_logger->print("End time of creating strip =%s\n\n",
						this->_logger->storeTime(tmp));
}

/**
 * To create strip from triangle array.
 * \note
 *
 * @param sco
 *
 * @author suzuki ryoutoku
 * @date 2007-10-30 New created.
 * @version 1.0
 */
int StripCreator::createTriangleStrip(StripCreatingOption* sco)
{
  char tmp[256];
  _logger->print(" Body name = %s cluster sum = %d\n", 
				 sco->_body->get_name(),
				 sco->_body->getClusterSum());
  int base_cluster_sum = sco->_body->getClusterSum();
  // Creating triangles, edge and vertex for strip.
  for( int i = 0; i < base_cluster_sum; i++ ){
	this->createTriangles(sco->_body->get_cluster(i));
	this->_logger->print("  triangle sum = %d\n", _triangles.size());
	// Creating edges for strip.
	this->_logger->print("  create edge start=%s\n", _logger->storeTime(tmp));
	this->createEdges(sco->_body->get_vertex_sum());
	this->_logger->print("  create edge end=%s\n", _logger->storeTime(tmp));
	this->setDegree();
  }
  createVertcies(sco->_body);

  for( int i = 0; i < base_cluster_sum; i++ ){
	/* create strip */
	Group* stripgroup = new Group( Group::TEXTURE, 
								   Group::STRIP_CLUSTER);
	Triangle* start=NULL;
	// unless all triangle is converted strip index
	while(NULL != (start = this->getStartTriangle(sco))){// to determine start
	  cout << "start triangle = " 
		   << start->_face_index 
		   << " degree = " 
		   << start->_degree
		   << endl;
	  // extend to three course (order is clockwise)
	  vector<strip::Triangle*> striplist1;
	  vector<strip::Triangle*> striplist2;
	  vector<strip::Triangle*> striplist3;
	  extendNormal(striplist1, start, start->_edges[0], 0);
	  extendNormal(striplist2, start, start->_edges[1], 1);
	  extendNormal(striplist3, start, start->_edges[2], 2);
	  
	  // extend to three course (order is counterclockwise)
	  vector<strip::Triangle*> reverse1;
	  vector<strip::Triangle*> reverse2;
	  vector<strip::Triangle*> reverse3;
	  extendReverse(reverse1, start, start->_edges[2], 2);
	  extendReverse(reverse2, start, start->_edges[0], 0);
	  extendReverse(reverse3, start, start->_edges[1], 1);
	  
	  // The counterclockwise is associated the clockwise
	  // no implement....
	  
	  // compare strip length
	  vector<strip::Triangle*> *striplist = &striplist1;
	  int strip1_sum = striplist1.size();
	  int strip2_sum = striplist2.size();
	  int strip3_sum = striplist3.size();
	  int edge_index = 0;
	  if( strip1_sum < strip2_sum && strip3_sum < strip2_sum ){
		edge_index = 1;
		striplist = &striplist2;
	  }else if( strip1_sum < strip3_sum && strip2_sum < strip3_sum ){
		edge_index = 2;
		striplist = &striplist3;
	  }
	  
	  // search true start triangle
	  
	  // build triangle
	  int sum = striplist->size() + 3;
	  Cluster* cluster = new TriangleStripCluster(striplist->size()+1, 
												  striplist->size()+3);
	  
	  // stored start triangle in strip buffer
	  int order[3];
	  order[0] = start->getThitherVertex(start->_edges[edge_index]);
	  if( start->_edges[edge_index]->_ascending == start ){
		order[1] = start->_edges[edge_index]->_first;
		order[2] = start->_edges[edge_index]->_second;
	  }else{
		order[2] = start->_edges[edge_index]->_first;
		order[1] = start->_edges[edge_index]->_second;
	  }
	  cluster->setPolygon(sco->_body,0, start->_face_index, order);

	  int triindex = 1;
	  int verindex = 3;
	  vector<strip::Triangle*>::iterator tri = striplist->begin();
	  Triangle* before = start;
	  start->notifyLeaving();
	  start->_state = strip::Triangle::USED;
	  while( tri != striplist->end() ){
		// To get vertex corresponding to edge
		order[0] = (*tri)->getAcrossVertex(before);
		cluster->setPolygon(sco->_body,
							triindex++,
							(*tri)->_face_index,
							order);
		(*tri)->_state = strip::Triangle::USED;
		(*tri)->notifyLeaving();
		before = (*tri);
		tri++;
	  }
	  stripgroup->addTarget(sco->_body->appendCluster(cluster));
	  striplist1.clear();
	  striplist2.clear();
	  striplist3.clear();
	  reverse1.clear();
	  reverse2.clear();
	  reverse3.clear();
	  this->refreshTriangleState();
	}
	_logger->print("  strip sum=%d\n", stripgroup->getTargetSum());
	sco->_body->appendGroup(stripgroup);
  }
  return 0;
}


/**
 * To store triangle information in working data
 * \note
 * 
 * @param triangle index array of triangle connectivity
 * @param faceindex global index of triangle
 * @param triangle_sum sum triangle
 *
 * @author suzuki ryoutoku
 * @date 2007-11-2
 * @version 1.0
 */
int StripCreator::createTriangles(Cluster* cluster)
{
  switch( cluster->get_type() ){
  case Cluster::TRIANGLE_CLUSTER:
	for( int i = 0; i < cluster->get_sum(); i ++ ){
	  int* conne = cluster->get_connectivity(i);
	  strip::Triangle tri1(conne[0],
						   conne[1],
						   conne[2]);
	  tri1._face_index = cluster->get_polygon_id(i);
	  this->_triangles.push_back(tri1);
	}
	break;
  case Cluster::RECTANGLE_CLUSTER:
	for( int i = 0; i < cluster->get_sum(); i ++ ){
	  int* conne = cluster->get_connectivity(i);
	  strip::Triangle tri1(conne[0],
						   conne[1],
						   conne[2]);
	  tri1._face_index = cluster->get_polygon_id(i);
	  this->_triangles.push_back(tri1);
	  strip::Triangle tri2(conne[0],
						   conne[2],
						   conne[3]);
	  tri2._face_index = cluster->get_polygon_id(i);
	  this->_triangles.push_back(tri2);
	}
	break;
  default:
	break;
  }
  return this->_triangles.size();
}

/**
 * This method creates edge information.
 * @author suzuki ryoutoku
 * @date 2007-10-31 New created.
 * @version 1.0
 */
int StripCreator::createEdges(int vertex_sum)
{
  int second_index[] = { 1, 2, 0};
  int edge_counter = 0;
  vector<int>	*vertex_has_line;

  vertex_has_line = new vector<int>[vertex_sum];
  
  if( this->_triangles.size() == 0 ) return -1;


  // To repeats sum of triangle times
  for( int i = 0; i < this->_triangles.size(); i ++ ){

	// each three edge
	for( int j = 0; j < 3; j ++){
	  strip::Edge edge;
	  bool flag = true;
	  
	  // determine start and end of the edge
	  edge._first = this->_triangles[i]._index[j];
	  edge._second = this->_triangles[i]._index[second_index[j]];

	  // To check the edge equal aleady creating edge
	  for( int k = 0; k < vertex_has_line[edge._first].size(); k++){
		int edge_index = (int)(vertex_has_line[edge._first][k]);
		if( edge._first == this->_edges[edge_index]._second ){
		  if( edge._second == this->_edges[edge_index]._first ){
			this->_triangles[i]._edges[j] = (Edge*)(edge_index);
			flag = false;
			break;
		  }
		}
	  }
	  if( flag != false ){
		for( int k = 0; k < vertex_has_line[edge._second].size(); k++){
		  int edge_index = (int)(vertex_has_line[edge._second][k]);
		  if( edge._first == this->_edges[edge_index]._second ){
			if( edge._second == this->_edges[edge_index]._first ){
			  this->_triangles[i]._edges[j] = (Edge*)(edge_index);
			  flag = false;
			  break;
			}
		  }
		}
	  }

	  // If the edge is not made yet, insert edge array
	  if( true == flag ){
		this->_triangles[i]._edges[j] = (Edge*)(this->_edges.size());
		vertex_has_line[edge._first].push_back(this->_edges.size());
		vertex_has_line[edge._second].push_back(this->_edges.size());
		this->_edges.push_back(edge);
		edge_counter++;
	  }
	}
  }
  //cout << "build edge end" << endl;

  //cout << "relative edge" << endl;
  for( int i = 0; i < this->_triangles.size(); i ++ ){
	for( int j = 0; j < 3; j ++){
	  int k = (int)(this->_triangles[i]._edges[j]);
	  if( this->_triangles[i]._index[j] 
		  == this->_edges[k]._second 
		  &&
		  this->_triangles[i]._index[second_index[j]]
		  == this->_edges[k]._first ){
		this->_edges[k]._descending = &(this->_triangles[i]);
		this->_triangles[i]._edges[j] = &(this->_edges[k]);
		this->_triangles[i]._edge_path[j] = false;
	  }else if(this->_triangles[i]._index[j] 
			   == this->_edges[k]._first 
			   &&
			   this->_triangles[i]._index[second_index[j]]
			   == this->_edges[k]._second ){
		this->_edges[k]._ascending = &(this->_triangles[i]);
		this->_triangles[i]._edges[j] = &(this->_edges[k]);
		this->_triangles[i]._edge_path[j] = true;
	  }

	}
  }


  for( int i = 0; i < vertex_sum; i ++ ){
	vertex_has_line[i].clear();
  }
  delete [] vertex_has_line;
  //cout << "relative edge end" << endl;

  
  return 0;
}

/**
 * This method creates vertices information.
 * \note
 * This method allocate vertices and set triangle index.
 * @author r-suzuki
 * @date 2009-1-13
 * @version 1.0
 */
int StripCreator::createVertcies(PolygonBody* body)
{
  _vertcies.resize(body->get_vertex_sum());
  for( size_t i = 0; i < _triangles.size(); i++ ){
	_vertcies[_triangles[i]._index[0]]._tri_index.push_back(i);
	_vertcies[_triangles[i]._index[1]]._tri_index.push_back(i);
	_vertcies[_triangles[i]._index[2]]._tri_index.push_back(i);
  }
  // sort according to degree density of vertex.
  sort( _vertcies.begin(), _vertcies.end() );
  return 0;
}

/**
 * @author suzuki ryoutoku
 * @date 2007-11-2
 * @version 1.0
 */
void StripCreator::display_edges(void)
{
  for(int i = 0; i < this->_edges.size(); i++){
	cout << this->_edges[i]._ascending <<" " 
		 << this->_edges[i]._descending << " ";
	cout << this->_edges[i]._second <<" "
		 << this->_edges[i]._first << endl;

  }
}

/**
 * This method give a start triangle pointer.
 * @author suzuki ryoutoku 
 * @date 2007-11-3
 * @version 1.0
 */
strip::Triangle* 
StripCreator::getStartTriangle(library::graphics::StripCreatingOption* sco)
{
  switch( sco->_start_option ){
  case IO_ORDER:
	// FILE IO order
	for( int i = 0; i < this->_triangles.size(); i ++){
	  if( this->_triangles[i]._state == 0 ){
		return &(this->_triangles[i]);
	  }
	}
	break;
  case ADJACENCE_DEGREE:
	// Search Least degree
	{
	  strip::Triangle* retval = NULL;
	  for( int i = 0; i < this->_triangles.size(); i ++){
		if( this->_triangles[i]._state == 0 ){
		  if( NULL == retval ){
			// When retval is not initialize 
			retval=&(this->_triangles[i]);

		  }else if( retval->_degree > _triangles[i]._degree ){
			retval=&(this->_triangles[i]);
		  }
		}
	  }
	  return retval;
	}
	break;
  case DENSITY_DEGREE:
	{
	  for( size_t i = 0; i < _vertcies.size(); i++ ){
		int index = _vertcies[i].getStartTriangle(&_triangles);
		if( index != -1 ){
		  return &(_triangles[index]);
		}
	  }
	}
	break;
  }
  return NULL;
}

/**
 * This method is extending strip frist counterclockwise.
 * @author suzuki ryoutoku
 * @date 2007-11-5
 * @version 1.0
 */
bool StripCreator::extendNormal(vector<strip::Triangle*> &striplist,
								strip::Triangle* start, 
								strip::Edge* edge,
								int edge_no)
{
  strip::Triangle* now_face = start;
  strip::Triangle* next_face = NULL;
  strip::Edge* now_edge = edge;
  strip::Edge* next_edge = NULL;
  int tri_state[3] = { strip::Triangle::NORMAL_EDGE_1,
					   strip::Triangle::NORMAL_EDGE_2,
					   strip::Triangle::NORMAL_EDGE_3};

  // kick-off triangle (value is false) is counterclockwise, next clockwise....
  // Turning direction is alternate counterclockwise and clockwise
  bool next_circle = false;

  if( edge == NULL ) return false;

  // unless next triangle is exist
  while( NULL != (next_face = now_edge->getNeighbourTriangle(now_face)) ){
	if( next_face == start ) break;
	// Second vertex is stored A of opengl buffer, Third is B of opengl buffer.
	// OpenGL buffer is alternate buffer A and buffer B.
	if( next_circle == false){
	  next_edge = next_face->findViaEdgeWithCurrentBufferA(now_edge);
	}else{
	  next_edge = next_face->findViaEdgeWithCurrentBufferB(now_edge);
	}
	next_circle ^= true;

	if( next_edge == NULL){
	  break;
	}
	
	// If next_face is already strip index
	if( next_face->_state & tri_state[edge_no] )	break;
	if( next_face->_state == strip::Triangle::USED )	break;
#if 0
	cout << "stripindex=" << striplist.size() <<" ";
	cout << "[" << next_circle << "] ";
	for( int k = 0; k < 3; k++ ){
	  if( now_face->_edges[k] == now_edge ){
		if( now_face->_edge_path[k] ){
		  cout << now_edge->_first << "=>" << now_edge->_second
			   << ":" << next_face->_face_index << endl;
		}else{
		  cout << now_edge->_second << "=>" << now_edge->_first
			   << ":" << next_face->_face_index << endl;
		}
	  }
	}
#endif
	// Sign candidate
	next_face->_state ^= tri_state[edge_no];
	striplist.push_back(next_face);
	now_edge = next_edge;
	now_face = next_face;
  }

  return true;
}

/**
 * This method is extending strip frist clockwise.
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-7-15
 */
bool StripCreator::extendReverse(vector<strip::Triangle*> &striplist,
								 strip::Triangle* start, 
								 strip::Edge* edge,
								 int edge_no)
{
  strip::Triangle* now_face = start;
  strip::Triangle* next_face = NULL;
  strip::Edge* now_edge = edge;
  strip::Edge* next_edge = NULL;
  int tri_state[3] = { strip::Triangle::NORMAL_EDGE_1,
					   strip::Triangle::NORMAL_EDGE_2,
					   strip::Triangle::NORMAL_EDGE_3};
  int rev_tri_state[3] = { strip::Triangle::REVERSE_EDGE_1,
						   strip::Triangle::REVERSE_EDGE_2,
						   strip::Triangle::REVERSE_EDGE_3};

  // kick-off triangle (value is true) is clockwise, next counterclockwise....
  // Turning direction is alternate clockwise and counterclockwise
  bool next_circle = true;
  if( edge == NULL ) return false;
  while( NULL != (next_face = now_edge->getNeighbourTriangle(now_face)) ){
	if( next_face == start ) break;
	// Second vertex is stored A of opengl buffer, Third is B of opengl buffer.
	// OpenGL buffer is alternate buffer A and buffer B.
	if( next_circle == false){
	  next_edge = next_face->findViaEdgeWithCurrentBufferA(now_edge);

	}else{
	  next_edge = next_face->findViaEdgeWithCurrentBufferB(now_edge);

	}

	next_circle ^= true;

	if( next_edge == NULL){
	  break;
	}
	
	// If next_face is already strip index?
	if( next_face->_state & tri_state[edge_no] )	break;
	if( next_face->_state & rev_tri_state[edge_no] )	break;
	if( next_face->_state == strip::Triangle::USED )	break;
	next_face->_state ^= rev_tri_state[edge_no];
	striplist.push_back(next_face);
	now_edge = next_edge;
	now_face = next_face;
  }
  return true;
}

/**
 * This method reset triangle's state.
 * @author r-suzuki
 * @date 2008-12-24
 * @version 1.0
 */
void StripCreator::refreshTriangleState(void)
{
  for( size_t i = 0; i < _triangles.size(); i++ ){
	if( _triangles[i]._state != strip::Triangle::USED ){
	  _triangles[i]._state = 0;
	}
  }
}


/**
 * This method set _triangles's degree property.
 * @author r-suzuki
 * @date 2009-1-5
 * @version 1.0
 */
void StripCreator::setDegree(void)
{
  for( int i = 0; i < this->_triangles.size(); i ++){
	int degree = 0;
	for( int j = 0; j < 3; j ++ ){
	  strip::Edge* edge = (this->_triangles[i]._edges[j]);
	  if( NULL != edge->getNeighbourTriangle(&(this->_triangles[i]))){
		degree++;
	  }
	}
	_triangles[i]._degree = degree;
  }
}
